home *** CD-ROM | disk | FTP | other *** search
/ Dr. Windows 3 / dr win3.zip / dr win3 / NEW_TECH / AWKSRC.ZIP / BUILTIN.C < prev    next >
C/C++ Source or Header  |  1993-09-27  |  24KB  |  1,129 lines

  1. /*
  2.  * builtin.c - Builtin functions and various utility procedures 
  3.  */
  4.  
  5. /* 
  6.  * Copyright (C) 1986, 1988, 1989, 1991, 1992 the Free Software Foundation, Inc.
  7.  * 
  8.  * This file is part of GAWK, the GNU implementation of the
  9.  * AWK Progamming Language.
  10.  * 
  11.  * GAWK is free software; you can redistribute it and/or modify
  12.  * it under the terms of the GNU General Public License as published by
  13.  * the Free Software Foundation; either version 2 of the License, or
  14.  * (at your option) any later version.
  15.  * 
  16.  * GAWK is distributed in the hope that it will be useful,
  17.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  19.  * GNU General Public License for more details.
  20.  * 
  21.  * You should have received a copy of the GNU General Public License
  22.  * along with GAWK; see the file COPYING.  If not, write to
  23.  * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  24.  */
  25.  
  26.  
  27. #include "awk.h"
  28.  
  29.  
  30. #ifndef SRANDOM_PROTO
  31. extern void srandom P((int seed));
  32. #endif
  33. extern char *initstate P((unsigned seed, char *state, int n));
  34. extern char *setstate P((char *state));
  35. extern long random P((void));
  36.  
  37. extern NODE **fields_arr;
  38. extern int output_is_tty;
  39.  
  40. static NODE *sub_common P((NODE *tree, int global));
  41.  
  42. #ifdef GFMT_WORKAROUND
  43. char *gfmt P((double g, int prec, char *buf));
  44. #endif
  45.  
  46. #ifdef _CRAY
  47. /* Work around a problem in conversion of doubles to exact integers. */
  48. #include <float.h>
  49. #define Floor(n) floor((n) * (1.0 + DBL_EPSILON))
  50. #define Ceil(n) ceil((n) * (1.0 + DBL_EPSILON))
  51.  
  52. /* Force the standard C compiler to use the library math functions. */
  53. extern double exp(double);
  54. double (*Exp)() = exp;
  55. #define exp(x) (*Exp)(x)
  56. extern double log(double);
  57. double (*Log)() = log;
  58. #define log(x) (*Log)(x)
  59. #else
  60. #define Floor(n) floor(n)
  61. #define Ceil(n) ceil(n)
  62. #endif
  63.  
  64. /* Builtin functions */
  65. NODE *
  66. do_exp(tree)
  67. NODE *tree;
  68. {
  69.     NODE *tmp;
  70.     double d, res;
  71. #ifndef exp
  72.     double exp P((double));
  73. #endif
  74.  
  75.     tmp= tree_eval(tree->lnode);
  76.     d = force_number(tmp);
  77.     free_temp(tmp);
  78.     errno = 0;
  79.     res = exp(d);
  80.     if (errno == ERANGE)
  81.         warning("exp argument %g is out of range", d);
  82.     return tmp_number((AWKNUM) res);
  83. }
  84.  
  85. NODE *
  86. do_index(tree)
  87. NODE *tree;
  88. {
  89.     NODE *s1, *s2;
  90.     register char *p1, *p2;
  91.     register int l1, l2;
  92.     long ret;
  93.  
  94.  
  95.     s1 = tree_eval(tree->lnode);
  96.     s2 = tree_eval(tree->rnode->lnode);
  97.     force_string(s1);
  98.     force_string(s2);
  99.     p1 = s1->stptr;
  100.     p2 = s2->stptr;
  101.     l1 = s1->stlen;
  102.     l2 = s2->stlen;
  103.     ret = 0;
  104.     if (IGNORECASE) {
  105.         while (l1) {
  106.             if (l2 > l1)
  107.                 break;
  108.             if (casetable[(int)*p1] == casetable[(int)*p2]
  109.                 && (l2 == 1 || strncasecmp(p1, p2, l2) == 0)) {
  110.                 ret = 1 + s1->stlen - l1;
  111.                 break;
  112.             }
  113.             l1--;
  114.             p1++;
  115.         }
  116.     } else {
  117.         while (l1) {
  118.             if (l2 > l1)
  119.                 break;
  120.             if (*p1 == *p2
  121.                 && (l2 == 1 || STREQN(p1, p2, l2))) {
  122.                 ret = 1 + s1->stlen - l1;
  123.                 break;
  124.             }
  125.             l1--;
  126.             p1++;
  127.         }
  128.     }
  129.     free_temp(s1);
  130.     free_temp(s2);
  131.     return tmp_number((AWKNUM) ret);
  132. }
  133.  
  134. NODE *
  135. do_int(tree)
  136. NODE *tree;
  137. {
  138.     NODE *tmp;
  139.     double floor P((double));
  140.     double ceil P((double));
  141.     double d;
  142.  
  143.     tmp = tree_eval(tree->lnode);
  144.     d = force_number(tmp);
  145.     if (d >= 0)
  146.         d = Floor(d);
  147.     else
  148.         d = Ceil(d);
  149.     free_temp(tmp);
  150.     return tmp_number((AWKNUM) d);
  151. }
  152.  
  153. NODE *
  154. do_length(tree)
  155. NODE *tree;
  156. {
  157.     NODE *tmp;
  158.     int len;
  159.  
  160.     tmp = tree_eval(tree->lnode);
  161.     len = force_string(tmp)->stlen;
  162.     free_temp(tmp);
  163.     return tmp_number((AWKNUM) len);
  164. }
  165.  
  166. NODE *
  167. do_log(tree)
  168. NODE *tree;
  169. {
  170.     NODE *tmp;
  171. #ifndef log
  172.     double log P((double));
  173. #endif
  174.     double d, arg;
  175.  
  176.     tmp = tree_eval(tree->lnode);
  177.     arg = (double) force_number(tmp);
  178.     if (arg < 0.0)
  179.         warning("log called with negative argument %g", arg);
  180.     d = log(arg);
  181.     free_temp(tmp);
  182.     return tmp_number((AWKNUM) d);
  183. }
  184.  
  185. /* %e and %f formats are not properly implemented.  Someone should fix them */
  186. /* Actually, this whole thing should be reimplemented. */
  187.  
  188. NODE *
  189. do_sprintf(tree)
  190. NODE *tree;
  191. {
  192. #define bchunk(s,l) if(l) {\
  193.     while((l)>ofre) {\
  194.       erealloc(obuf, char *, osiz*2, "do_sprintf");\
  195.       ofre+=osiz;\
  196.       osiz*=2;\
  197.     }\
  198.     memcpy(obuf+olen,s,(l));\
  199.     olen+=(l);\
  200.     ofre-=(l);\
  201.   }
  202.  
  203.     /* Is there space for something L big in the buffer? */
  204. #define chksize(l)  if((l)>ofre) {\
  205.     erealloc(obuf, char *, osiz*2, "do_sprintf");\
  206.     ofre+=osiz;\
  207.     osiz*=2;\
  208.   }
  209.  
  210.     /*
  211.      * Get the next arg to be formatted.  If we've run out of args,
  212.      * return "" (Null string) 
  213.      */
  214. #define parse_next_arg() {\
  215.   if(!carg) { toofew = 1; break; }\
  216.   else {\
  217.     arg=tree_eval(carg->lnode);\
  218.     carg=carg->rnode;\
  219.   }\
  220.  }
  221.  
  222.     NODE *r;
  223.     int toofew = 0;
  224.     char *obuf;
  225.     int osiz, ofre, olen;
  226.     static char chbuf[] = "0123456789abcdef";
  227.     static char sp[] = " ";
  228.     char *s0, *s1;
  229.     int n0;
  230.     NODE *sfmt, *arg;
  231.     register NODE *carg;
  232.     long fw, prec, lj, alt, big;
  233.     long *cur;
  234.     long val;
  235. #ifdef sun386        /* Can't cast unsigned (int/long) from ptr->value */
  236.     long tmp_uval;    /* on 386i 4.0.1 C compiler -- it just hangs */
  237. #endif
  238.     unsigned long uval;
  239.     int sgn;
  240.     int base;
  241.     char cpbuf[30];        /* if we have numbers bigger than 30 */
  242.     char *cend = &cpbuf[30];/* chars, we lose, but seems unlikely */
  243.     char *cp;
  244.     char *fill;
  245.     double tmpval;
  246.     char *pr_str;
  247.     int ucasehex = 0;
  248.     char signchar = 0;
  249.     int len;
  250.  
  251.  
  252.     emalloc(obuf, char *, 120, "do_sprintf");
  253.     osiz = 120;
  254.     ofre = osiz - 1;
  255.     olen = 0;
  256.     sfmt = tree_eval(tree->lnode);
  257.     sfmt = force_string(sfmt);
  258.     carg = tree->rnode;
  259.     for (s0 = s1 = sfmt->stptr, n0 = sfmt->stlen; n0-- > 0;) {
  260.         if (*s1 != '%') {
  261.             s1++;
  262.             continue;
  263.         }
  264.         bchunk(s0, s1 - s0);
  265.         s0 = s1;
  266.         cur = &fw;
  267.         fw = 0;
  268.         prec = 0;
  269.         lj = alt = big = 0;
  270.         fill = sp;
  271.         cp = cend;
  272.         s1++;
  273.  
  274. retry:
  275.         --n0;
  276.         switch (*s1++) {
  277.         case '%':
  278.             bchunk("%", 1);
  279.             s0 = s1;
  280.             break;
  281.  
  282.         case '0':
  283.             if (fill != sp || lj)
  284.                 goto lose;
  285.             if (cur == &fw)
  286.                 fill = "0";    /* FALL through */
  287.         case '1':
  288.         case '2':
  289.         case '3':
  290.         case '4':
  291.         case '5':
  292.         case '6':
  293.         case '7':
  294.         case '8':
  295.         case '9':
  296.             if (cur == 0)
  297.                 goto lose;
  298.             *cur = s1[-1] - '0';
  299.             while (n0 > 0 && *s1 >= '0' && *s1 <= '9') {
  300.                 --n0;
  301.                 *cur = *cur * 10 + *s1++ - '0';
  302.             }
  303.             goto retry;
  304.         case '*':
  305.             if (cur == 0)
  306.                 goto lose;
  307.             parse_next_arg();
  308.             *cur = (long) force_number(arg);
  309.             free_temp(arg);
  310.             goto retry;
  311.         case ' ':        /* print ' ' or '-' */
  312.         case '+':        /* print '+' or '-' */
  313.             signchar = *(s1-1);
  314.             goto retry;
  315.         case '-':
  316.             if (lj || fill != sp)
  317.                 goto lose;
  318.             lj++;
  319.             goto retry;
  320.         case '.':
  321.             if (cur != &fw)
  322.                 goto lose;
  323.             cur = ≺
  324.             goto retry;
  325.         case '#':
  326.             if (alt)
  327.                 goto lose;
  328.             alt++;
  329.             goto retry;
  330.         case 'l':
  331.             if (big)
  332.                 goto lose;
  333.             big++;
  334.             goto retry;
  335.         case 'c':
  336.             parse_next_arg();
  337.             if (arg->flags & NUMBER) {
  338. #ifdef sun386
  339.                 tmp_uval = arg->numbr; 
  340.                 uval= (unsigned long) tmp_uval;
  341. #else
  342.                 uval = (unsigned long) arg->numbr;
  343. #endif
  344.                 cpbuf[0] = (char) uval;
  345.                 prec = 1;
  346.                 pr_str = cpbuf;
  347.                 goto dopr_string;
  348.             }
  349.             if (! prec)
  350.                 prec = 1;
  351.             else if (prec > (signed) arg->stlen)
  352.                 prec = arg->stlen;
  353.             pr_str = arg->stptr;
  354.             goto dopr_string;
  355.         case 's':
  356.             parse_next_arg();
  357.             arg = force_string(arg);
  358.             if (!prec || prec > (signed) arg->stlen)
  359.                 prec = arg->stlen;
  360.             pr_str = arg->stptr;
  361.  
  362.     dopr_string:
  363.             if (fw > prec && !lj) {
  364.                 while (fw > prec) {
  365.                     bchunk(sp, 1);
  366.                     fw--;
  367.                 }
  368.             }
  369.             bchunk(pr_str, (int) prec);
  370.             if (fw > prec) {
  371.                 while (fw > prec) {
  372.                     bchunk(sp, 1);
  373.                     fw--;
  374.                 }
  375.             }
  376.             s0 = s1;
  377.             free_temp(arg);
  378.             break;
  379.         case 'd':
  380.         case 'i':
  381.             parse_next_arg();
  382.             val = (long) force_number(arg);
  383.             free_temp(arg);
  384.             if (val < 0) {
  385.                 sgn = 1;
  386.                 val = -val;
  387.             } else
  388.                 sgn = 0;
  389.             do {
  390.                 *--cp = '0' + val % 10;
  391.                 val /= 10;
  392.             } while (val);
  393.             if (sgn)
  394.                 *--cp = '-';
  395.             else if (signchar)
  396.                 *--cp = signchar;
  397.             if (prec > fw)
  398.                 fw = prec;
  399.             prec = cend - cp;
  400.